/**
 * This is a test program to simulate the client behavior for the Project 3
 */

#include "syscall.h"

/**
 * This function tests the Lock creation and destroy for server/client interaction
 */
void testcase1()
{

	int lockId,i,temp;
	char *lockname;
	lockname = "lock000";

	Print("*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test1]Creating a lock with name \"combolock\"\n");
	lockId = CreateLock((char *)"combolock",9);
	Print1("Lock created with ID = %d\n",lockId);

	Print("--------------------------------------------------------\n");
	Print("[Test2]Creating a lock,which is already existing...Server should return an id instead of creating lock\n");
	Print1("Lock id returned to client = %d\n",(CreateLock((char *)"combolock",9)));

	Print("--------------------------------------------------------\n");
	Print("[Test3]Destroying the lock \"combolock\"\n");
	DestroyLock(lockId);
	DestroyLock(lockId);

	Print("\n\n*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");

	Print("[Test4]Destroying the lock \"combolock\" : which is already destroyed on server\n");
	DestroyLock(lockId);

	Print("--------------------------------------------------------\n");
	Print("[Test5]number of locks exceeding the limit on server\n[5 Additional locks created to simulate error]\n");

	for(i=0;i<505;i++)
	{
		temp = i;
		*(lockname+4) = (char)((temp/100)+'0');
		temp = temp%100;
		*(lockname+5) = (char)((temp/10)+'0');
		temp = temp%10;
		*(lockname+6) = (char)(temp+'0');
		CreateLock(lockname,7);
	}

	Print("This temporary delay was generated to prove the correctness of the output at server end\nTo proceed enter any number :");
	i=Scan();

	for(i=0;i<500;i++)
	{
		DestroyLock(i);
	}

}

void testcase2()
{
	int cvId,temp,i;
	char *cvName;
	cvName = "cond0000";

	Print("*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");


	Print("[Test1]Creating a cv with name \"combocv\"\n");
	cvId = CreateCondition((char *)"combocv",7);
	Print1("CV created with ID = %d\n",cvId);

	Print("--------------------------------------------------------\n");
	Print("[Test2]Creating a cv,which is already existing...Server should return an id instead of creating cv\n");
	Print1("Lock id returned to client = %d\n",(CreateCondition((char *)"combocv",7)));

	Print("--------------------------------------------------------\n");
	Print("[Test3]Destroying the cv \"combocv\"\n");
	DestroyCondition(cvId);
	DestroyCondition(cvId);

	Print("\n\n*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");

	Print("[Test4]Destroying the cv \"combocv\" : which is already destroyed on server\n");
	DestroyCondition(cvId);

	Print("--------------------------------------------------------\n");

	Print("[Test5]number of cvs exceeding the limit on server\n[5 Additional CV's created to simulate error]\n");
	for(i=0;i<1005;i++)
	{
		temp = i;
		*(cvName+4) = (char)((temp/1000)+'0');
		temp = temp%1000;
		*(cvName+5) = (char)((temp/100)+'0');
		temp = temp%100;
		*(cvName+6) = (char)(temp/10+'0');
		temp = temp%10;
		*(cvName+7) = (char)(temp+'0');
		CreateCondition(cvName,8);
	}


	Print("This temporary delay was generated to prove the correctness of the output at server end\nTo proceed with removal of temporary test objects enter any number : ");
	i=Scan();

	for(i=0;i<1000;i++)
	{
		DestroyCondition(i);
	}

}

/**
 * This testcase ensures that the Acquire / Release lock mechanism works properly for client/server interaction
 */
void testcase3()
{
	int lockId;

	Print("*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");

	Print("[Test1]Acquire \"combolock\"\n");
	lockId = CreateLock((char *)"combolock",9);
	Acquire(lockId);

	Print("--------------------------------------------------------\n");
	Print("[Test2]Release \"combolock\"\n");
	Release(lockId);

	Print("\n\n*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");

	Print("[Test3]Try to Acquire non-existing lock \"nolock\"\n");
	Acquire(1000);
	Print("--------------------------------------------------------\n");
	Print("[Test4]Try to Release non-existing lock \"nolock\"\n");
	Release(1000);

	Print("--------------------------------------------------------\n");
	Print("Deleting the locks created to simulate this test-case\n");
	DestroyLock(lockId);

}

/**
 * This testcase ensures that the wait/signal/broadcast works properly for client/server interaction
 */
void testcase4()
{
	int lockId,cvId;

	lockId = CreateLock((char *)"combolock",9);
	cvId = CreateCondition("combocv",7);
	Print2("Client is waiting on cv \"combocv\" : %d with lock \"combolock\" : %d\n",cvId,lockId);

	Acquire(lockId);
	Wait(cvId,lockId);
	Release(lockId);
}

/*
 * This function signals the client waiting for "combocv"
 */
void testcase5()
{

	int lockId,cvId;

	lockId = CreateLock((char *)"combolock",9);

	cvId = CreateCondition("combocv",7);

	Print2("Client has signaled for another client waiting on cv \"combocv\" : %d with lock \"combolock\" : %d\n",cvId,lockId);
	Signal(cvId,lockId);

	Release(lockId);

	DestroyCondition(cvId);
	DestroyLock(lockId);

}

/*
 * This function broadcasts to the client waiting for "combocv"
 */
void testcase6()
{

	int lockId,cvId;

	lockId = CreateLock((char *)"combolock",9);
	cvId = CreateCondition("combocv",7);

	Print2("Client has Broadcasted for another client waiting on cv \"combocv\" : %d with lock \"combolock\" : %d\n",cvId,lockId);

	Broadcast(cvId,lockId);
	Release(lockId);

	DestroyCondition(cvId);
	DestroyLock(lockId);

}


/*
 * This function simulates the ping-pong behaviour
 */
void testcase7a()
{

	int lockId,i,cvId;

	lockId = CreateLock((char *)"combolock",9);
	cvId = CreateCondition("combocv",7);

	Acquire(lockId);
	Print2("Client is waiting on cv \"combocv\" : %d with lock \"combolock\" : %d\n",cvId,lockId);
	Wait(cvId,lockId);
	Release(lockId);
	Print("\nThis temporary delay is generated to wait for commencing ping-pong signal to other client machine\nEnter a number : ");
	i=Scan();
	Signal(cvId,lockId);

	DestroyCondition(cvId);
	DestroyLock(lockId);
}

/*
 * This function simulates for the ping-pong
 */
void testcase7b()
{

	int lockId,cvId;
	Print("Please ensure that test-case number 7 has been started before this test-case\n");

	lockId = CreateLock((char *)"combolock",9);
	cvId = CreateCondition("combocv",7);
	Signal(cvId,lockId);
	Acquire(lockId);
	Print2("Client is waiting on cv \"combocv\" : %d with lock \"combolock\" : %d\n",cvId,lockId);
	Wait(cvId,lockId);
	Release(lockId);


}

/**
 * This test-case is to simulate Positive and negative test-case for Monitor Variables
 */
void testcase9()
{
	int temp,i;
	char* mvName;

	int mvId;
	mvName="MtVr000";
	Print("\n\n*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test1]Creating a MV with name \"testMV\"\n");
	mvId = CreateMV((char *)"testMV",6,1);
	Print1("MV created with ID = %d\n",mvId);

	Print("--------------------------------------------------------\n");
	Print("[Test2]Creating a mv,which is already existing...Server should return an id instead of creating mv\n");
	Print1("MV id returned to client = %d\n",CreateMV((char *)"testMV",6,1));

	Print("--------------------------------------------------------\n");
	Print("[Test3]Destroying the MV \"testMV\"\n");
	DestroyMV(mvId);
	DestroyMV(mvId);

	Print("\n\n*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test4] Creating MV of more than Array Size\n");
	CreateMV("testMV",6,100);
	Print("--------------------------------------------------------\n");

	Print("[Test5]number of MVS exceeding the limit on server\n[5 Additional MV's created to simulate error]\n");
	for(i=0;i<505;i++)
	{
		temp = i;
		*(mvName+4) = (char)((temp/100)+'0');
		temp = temp%100;
		*(mvName+5) = (char)((temp/10)+'0');
		temp = temp%10;
		*(mvName+6) = (char)(temp+'0');
		CreateMV(mvName,7,1);
	}

	Print("--------------------------------------------------------\n");
	Print("Deleteing all the MV that are created to check other test cases.\n");
	for(i=0;i<500;i++)
	{
		DestroyMV(i);
	}
	Print("--------------------------------------------------------\n");

	Print("[Test6]Destroying the MV \"testMV\" : which is already destroyed on server\n");
	DestroyMV(mvId);

}

/**
 * This function simulate positive and negative test-cases for setMV and getMV functionalities
 */
void testcase10()
{
	int mvId,i;
	Print("\n\n*********************************************************\n");
	Print("POSITIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test1]Calling Set on a MV with name \"testMV\" to set value to 1\n");
	mvId = CreateMV((char *)"testMV",6,1);
	SetMV(mvId,0,1);
	Print("--------------------------------------------------------\n");
	Print("[Test2]Calling Get on a MV with name \"testMV\". Value returned should be 1\n");
	i=GetMV(mvId,0);
	Print1("Value returned from Get is :%d. \n",i);
	DestroyMV(mvId);

	Print("\n\n*********************************************************\n");
	Print("NEGATIVE TEST CASES\n");
	Print("*********************************************************\n");
	Print("[Test3]Calling Set on a MV that is out of range of maximum MVS\n");
	SetMV(10000,0,1);
	SetMV(-3,0,1);
	Print("--------------------------------------------------------\n");
	Print("[Test4]Calling Set on a MV that is not created\n");
	SetMV(10,0,1);
	Print("--------------------------------------------------------\n");
	Print("[Test5]Calling Set on a MV invalid arrayIndex\n");
	mvId = CreateMV((char *)"testMV",6,1);
	SetMV(mvId,10,10);

	Print("--------------------------------------------------------\n");
	Print("[Test6]Calling Get on a MV that is out of range of maximum MVS\n");
	i=GetMV(10000,1);
	i=GetMV(-3,0);
	Print("--------------------------------------------------------\n");
	Print("[Test7]Calling Get on a MV that is not created\n");
	i=GetMV(10,0);
	Print("--------------------------------------------------------\n");
	Print("[Test8]Calling Get on a MV invalid arrayIndex\n");
	mvId = CreateMV((char *)"testMV",6,1);
	i=GetMV(mvId,10);

}

/**
 * Secondary function to simulate the proper working for Monitor Variables between process
 */
testcase11b()
{

	int mvId,i;
	mvId = CreateMV((char *)"testMV",6,1);
	Print("[Test1]Calling Get on a MV with name \"testMV\". Value returned should be 1\n");
	i=GetMV(mvId,0);
	Print1("Value returned from Get is :%d. \n",i);
	Print("--------------------------------------------------------\n");
	Print("[Test2]Calling Set on a MV with name \"testMV\" to set value to 100\n");

	SetMV(mvId,0,100);
	Print("--------------------------------------------------------\n");
	Print("[Test3]Calling Get on a MV with name \"testMV\". Value returned should be 100\n");

	i=GetMV(mvId,0);
	Print1("Value returned from Get is :%d. \n",i);
	DestroyMV(mvId);
}

/**
 * Primary function to simulate the proper working for Monitor Variables between process
 */
testcase11a()
{
	int mvId,i;
	mvId = CreateMV((char *)"testMV",6,1);
	Print("--------------------------------------------------------\n");
	Print("Calling Set on a MV with name \"testMV\" to set value to 1\n");

	SetMV(mvId,0,1);

	Print("\n\nPlease start testcase 12 : part2 from another terminal before commencing\n");
	Print("This temporary delay generated to check the UPDATE on MV by other process\nEnter a number : ");
	i=Scan();
	Print("--------------------------------------------------------\n");
	Print("Calling Get on a MV with name \"testMV\". Value returned should be 100\n");

	i=GetMV(mvId,0);
	Print1("Value returned from Get is :%d. \n",i);
	DestroyMV(mvId);
}


void main()
{
	int testcase;

	Print("  1. CreateLock / DestroyLock System call Tests\n");
	Print("  2. CreateCondition / DestroyCondition System call Tests\n");
	Print("  3. Acquire / Release System call Tests\n");
	Print("  4. Part1 : Simulate A waiting client\n");
	Print("  5. Part2 : Signal client\n");
	Print("  6. Part3 : Broadcast client\n");
	Print("  7. Part1 : wait-signal ping-pong simulation\n");
	Print("  8. Part2 : wait-signal ping-pong simulation\n");
	Print("  9. CreateMV / DestroyMV System call Tests\n");
	Print(" 10. Tests Set and Get functions for MV\n");
	Print(" 11. Part1 : Update on MV between multiple process.\n");
	Print(" 12. Part2 : Update on MV between multiple process.\n");
	Print("\n");


	Print("Enter Choice:\n");

	testcase=Scan();

	Print("\n\n");

	switch(testcase)
	{
	case 1:
		testcase1();
		break;
	case 2:
		testcase2();
		break;
	case 3:
		testcase3();
		break;
	case 4:
		testcase4();
		break;
	case 5:
		testcase5();
		break;
	case 6:
		testcase6();
		break;
	case 7:
		testcase7a();
		break;
	case 8:
		testcase7b();
		break;
	case 9:
		testcase9();
		break;
	case 10:
		testcase10();
		break;
	case 11:
		testcase11a();
		break;
	case 12:
		testcase11b();
		break;
	default:
		Print("Please select a proper test-case choice\n");
	}

	Exit(0);
}
